﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace I3.AgenteIA.Dominio.Gramatica
{
    public class SentencaInterpreter : ISentencaInterpreter
    {
        /// <summary>
        /// Armazena o repositorio de acesso aos dados da gramatica
        /// </summary>
        private IRepositorioGramatica _repositorioGramatica;

        /// <summary>
        /// Construtor padrão da factory
        /// </summary>
        /// <param name="repositorioGramatica">Repositorio de acesso aos dados gramaticais</param>
        public SentencaInterpreter(IRepositorioGramatica  repositorioGramatica)
        {
            _repositorioGramatica = repositorioGramatica;
        }

        protected SentencaInterpreter() { }

        /// <summary>
        /// Cria a instancia das sentenças com base no texto recebido por parametro
        /// </summary>
        /// <param name="texto">Texto de entrada</param>
        /// <returns>Instancia das sentenças</returns>
        public virtual IEnumerable<Sentenca> Interpretar(Oracao oracao)
        {
            // recupera o texto da oração e insere em uma 
            // variavel auxiliar.
            string texto = oracao.Texto;

            // Recupera os sinais finalizadores de sentencas configurador no sistema
            IEnumerable<string> finalizadores = _repositorioGramatica.GetSinalByFinalizador(true).Select(o => o.Texto);
            IList<char> caracteres = new List<char>(texto.ToArray());

            // Verifica se o texto informado tem algum finalizador
            // Caso não. Apenas retorna a instancia de uma nova sentença sem 
            // realizar qualquer outro tipo de analise no texto.
            if (!(from o in caracteres where finalizadores.Contains(o.ToString()) select o).Any())
            {
                Sentenca tmpSentenca = oracao.CriarSentenca(texto.Trim());
                return new Sentenca[] { tmpSentenca };
            }

            // Se o ultimo caracter do texto não for um finalizador
            // conhecido, um espaço deverá ser incluido no final do espaço
            if (!finalizadores.Contains(caracteres[(caracteres.Count - 1)].ToString()))
                texto += " ";
            
            // Recupera o posicionamento dos elementos finalizadores
            List<int> posicoes = new List<int>();
            List<int> posicoesCandidatas = this.ObterPosicaoFinalizadores(caracteres.ToArray(), finalizadores.ToArray());
            
            // Realiza uma analise em todos os caracteres finalizadores encontrados 
            // no texto removendo aqueles que estão repetidos ou que não estao atuando 
            // o papel de finalizador de sentença
            for (int posicaoAtual = 0, posicaoTotal = posicoesCandidatas.Count; posicaoAtual < posicaoTotal; posicaoAtual++)
            {
                // Ignora os caracteres finalizadores que precede um outro
                // caractere finalizador.
                /*
                if (((posicaoAtual+1)==posicaoTotal) || !((posicoesCandidatas[posicaoAtual + 1] - posicoesCandidatas[posicaoAtual]) == 1))
                {
                    // Insere a posição na lista definitiva
                    posicoes.Add(posicoesCandidatas[posicaoAtual]);
                }
                 * */

                int posicaoParaValidacao = (posicoesCandidatas[posicaoAtual]+1);


                if((posicaoParaValidacao) >= caracteres.Count)
                {
                    // Insere a posição na lista definitiva
                    posicoes.Add(posicoesCandidatas[posicaoAtual]);
                    continue;
                }


                if ( ( char.IsWhiteSpace(caracteres[posicaoParaValidacao]) ))
                {
                    // Insere a posição na lista definitiva
                    posicoes.Add(posicoesCandidatas[posicaoAtual]);
                    continue;
                }
            }

            // Realiza uma analise em todos os caracteres finalizadores
            // encontrados no texto informado por parametro.
            List<Sentenca> sentencas = new List<Sentenca>();
            for (int posicaoAtual = 0, posicaoTotal = posicoes.Count(); posicaoAtual < posicaoTotal; posicaoAtual++)
            {
                // Recupera a posição inicial e a posicao final
                // da sentença com base no finalizador candidato
                int posicaoInicio = (posicaoAtual == 0 ? 0 : (posicoes[posicaoAtual-1]+1));
                int posicaoFinal = (posicoes[posicaoAtual]+1);

                // Recupera a string da sentenca
                string sentenca = texto.Substring(posicaoInicio, (posicaoFinal - posicaoInicio));
                
                // Insere a nova sentença na lista de sentenças que setão retornadas
                sentencas.Add( oracao.CriarSentenca(sentenca.Trim()) );
            }

            // Retorna a instancia das sentenças
            return sentencas;
        }

        /// <summary>
        /// Recupera o posicionamento dos caracteres finalizadores da 
        /// </summary>
        private List<int> ObterPosicaoFinalizadores(char[] caracteres, string[] finalizadores)
        {
            // TODO: Melhorar a performance do código usando os recuros do LINQ.
            List<int> posicoes = new List<int>();
            for (int caracterAtual = 0; caracterAtual < caracteres.Count(); caracterAtual++)
            {
                for (int finalizadorAtual = 0; finalizadorAtual < finalizadores.Count(); finalizadorAtual++)
                {
                    if(caracteres[caracterAtual].ToString() == finalizadores[finalizadorAtual])
                        posicoes.Add(caracterAtual);
                }
            }

            if (posicoes.Last() != (caracteres.Length - 1))
            {
                posicoes.Add(caracteres.Length);
            }

            return posicoes;
        }
    }
}
